import torch


def cxcywh_to_xyxy(cxcywh):
    """
    将批量的中心坐标和宽高 `(cx, cy, w, h)` 转换为批量的边界框左上角和右下角坐标 `(x_min, y_min, x_max, y_max)`。
    输入:
        cxcy: 张量，形状为 [N, 4]，其中每行包含 `(cx, cy, w, h)`。
    输出:
        张量，形状为 [N, 4]，其中每行包含 `(x_min, y_min, x_max, y_max)`。
    """
    cx, cy, w, h = cxcywh[:, 0], cxcywh[:, 1], cxcywh[:, 2], cxcywh[:, 3]
    x_min = cx - w / 2
    y_min = cy - h / 2
    x_max = cx + w / 2
    y_max = cy + h / 2
    return torch.stack([x_min, y_min, x_max, y_max], dim=1)

def xyxy_to_cxcywh(xyxy):
    """
    将批量的边界框左上角和右下角坐标 `(x_min, y_min, x_max, y_max)` 转换为批量的中心坐标和宽高 `(cx, cy, w, h)`。
    输入:
        xy: 张量，形状为 [N, 4]，其中每行包含 `(x_min, y_min, x_max, y_max)`。
    输出:
        张量，形状为 [N, 4]，其中每行包含 `(cx, cy, w, h)`。
    """
    x_min, y_min, x_max, y_max = xyxy[:, 0], xyxy[:, 1], xyxy[:, 2], xyxy[:, 3]
    cx = (x_min + x_max) / 2
    cy = (y_min + y_max) / 2
    w = x_max - x_min
    h = y_max - y_min
    return torch.stack([cx, cy, w, h], dim=1)

def gcxgcy_to_cxcy(gcxgcy, priors_cxcy):
    """
    将归一化偏移量 `(gcxgcy)` 解码为实际的中心坐标和宽高 `(cxcy)`。
    输入:
        gcxgcy: 张量，形状为 [N, 4]，包含 `(gcx, gcy, gw, gh)`。
        priors_cxcy: 张量，形状为 [N, 4]，包含锚框的 `(cx, cy, w, h)`。
    输出:
        张量，形状为 [N, 4]，包含解码后的 `(cx, cy, w, h)`。
    """
    cx = gcxgcy[:, 0] * priors_cxcy[:, 2] / 10 + priors_cxcy[:, 0]
    cy = gcxgcy[:, 1] * priors_cxcy[:, 3] / 10 + priors_cxcy[:, 1]
    w = torch.exp(gcxgcy[:, 2] / 5) * priors_cxcy[:, 2]
    h = torch.exp(gcxgcy[:, 3] / 5) * priors_cxcy[:, 3]
    return torch.stack([cx, cy, w, h], dim=1)

def cxcy_to_gcxgcy(cxcy, priors_cxcy):
    """
    将实际的中心坐标和宽高 `(cxcy)` 编码为归一化偏移量 `(gcxgcy)`。
    输入:
        cxcy: 张量，形状为 [N, 4]，包含 `(cx, cy, w, h)`。
        priors_cxcy: 张量，形状为 [N, 4]，包含锚框的 `(cx, cy, w, h)`。
    输出:
        张量，形状为 [N, 4]，包含编码后的 `(gcx, gcy, gw, gh)`。
    """
    gcx = (cxcy[:, 0] - priors_cxcy[:, 0]) / (priors_cxcy[:, 2] / 10)
    gcy = (cxcy[:, 1] - priors_cxcy[:, 1]) / (priors_cxcy[:, 3] / 10)
    gw = torch.log(cxcy[:, 2] / priors_cxcy[:, 2]) * 5
    gh = torch.log(cxcy[:, 3] / priors_cxcy[:, 3]) * 5
    return torch.stack([gcx, gcy, gw, gh], dim=1)
